package com.zwf.checkstyledemo1;

import com.puppycrawl.tools.checkstyle.*;
import com.puppycrawl.tools.checkstyle.api.*;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

public class CheckstyleRunner {

    int x;
    String y;

    public static void main(String[] args) {
        // 1. 配置检查参数
        String sourcePath = "src/main/java"; // 要检查的源代码路径
        String configPath = "classpath:customer_checks.xml"; // Checkstyle配置文件路径

        // 2. 执行检查
//        List<Violation> violations = runCheckstyle(sourcePath, configPath);

        // 3. 输出结果
        printResults(sourcePath, configPath);
    }

    /**
     * 执行Checkstyle静态代码检查
     *
     * @param sourcePath 要检查的源代码路径（文件或目录）
     * @param configPath Checkstyle配置文件路径
     * @return 违规信息列表
     */
    public static List<Violation> runCheckstyle(String sourcePath, String configPath) {
        List<Violation> violations = new ArrayList<>();

        try {
            // 创建Checkstyle配置
            Configuration config = ConfigurationLoader.loadConfiguration(
                    configPath,
                    new PropertiesExpander(System.getProperties()),
                    ConfigurationLoader.IgnoredModulesOptions.OMIT
            );

//            Configuration config = createCustomConfig();

            // 创建Checker实例
            Checker checker = new Checker();
            checker.setModuleClassLoader(Checker.class.getClassLoader());
            checker.configure(config);

            // 添加自定义监听器收集结果
            ViolationCollector listener = new ViolationCollector();
            checker.addListener(listener);

            // 处理文件或目录
            File source = new File(sourcePath);
            if (source.isDirectory()) {
                processDirectory(checker, source);
            } else {
                processFile(checker, source);
            }

            // 获取结果并清理资源
            violations = listener.getViolations();
            checker.destroy();

        } catch (Exception e) {
            System.err.println("Checkstyle执行出错: " + e.getMessage());
            e.printStackTrace();
        }

        return violations;
    }

    /**
     * 处理目录中的所有Java文件
     */
    private static void processDirectory(Checker checker, File directory) throws CheckstyleException, IOException {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    processDirectory(checker, file);
                } else if (file.getName().endsWith(".java")) {

                    processFile(checker, file);
                }
            }
        }
    }

    /**
     * 处理单个Java文件
     */
    private static void processFile(Checker checker, File file) throws CheckstyleException, IOException {
        checker.process(Collections.singletonList(new FileText(file.getAbsoluteFile(), StandardCharsets.UTF_8.name()).getFile()));
    }

    private static void printResults(String sourcePath, String configPath) {
        List<Violation> violations = new ArrayList<>();

        try {
            // 创建Checkstyle配置
            Configuration config = ConfigurationLoader.loadConfiguration(
                    configPath,
                    new PropertiesExpander(System.getProperties()),
                    ConfigurationLoader.IgnoredModulesOptions.OMIT
            );

//            Configuration config = createCustomConfig();

            // 创建Checker实例
            Checker checker = new Checker();
            checker.setModuleClassLoader(Checker.class.getClassLoader());
            checker.configure(config);

            // 添加自定义监听器收集结果
            ViolationCollector listener = new ViolationCollector();
            checker.addListener(listener);

            // 处理文件或目录
            File source = new File(sourcePath);
            if (source.isDirectory()) {
                processDirectory(checker, source);
            } else {
                processFile(checker, source);
            }

            // 获取结果并清理资源
            violations = listener.getViolations();
            checker.destroy();

            if (violations.isEmpty()) {
                System.out.println("✓ 检查完成！未发现任何问题。");
                return;
            }

            int totalLines = 0;
            int totalCommentLines = 0;

            if (listener != null) {
                totalLines = listener.getTotalLines();
                totalCommentLines = listener.getTotalCommentLines();
            }
            System.out.println("============== 代码统计报告 ==============");
            System.out.printf("总代码行数: %d%n", totalLines);
            System.out.printf("总注释行数: %d%n", totalCommentLines);
            System.out.printf("注释率: %.2f%%%n", totalLines > 0 ? (totalCommentLines * 100.0 / totalLines) : 0);
            System.out.println("==========================================");

            violations = violations.stream().filter(i -> i.getLine() != 1).collect(Collectors.toList());
            System.out.println("==========================================");
            System.out.println("❌ 发现 " + violations.size() + " 个问题：");
            System.out.println("==========================================");

            // 按文件分组显示结果
            Map<String, List<Violation>> groupedViolations = new TreeMap<>();
            for (Violation violation : violations) {
                String fileName = new File(violation.getFileName()).getName();
                groupedViolations.computeIfAbsent(fileName, k -> new ArrayList<>()).add(violation);
            }

            for (Map.Entry<String, List<Violation>> entry : groupedViolations.entrySet()) {
                System.out.println("\n文件: " + entry.getKey());
                for (Violation v : entry.getValue()) {
                    System.out.printf("  行 %4d: [%-20s] %s%n",
                            v.getLine(), v.getSource(), v.getMessage());
                }
            }

            System.out.println("\n==========================================");
            System.out.println("检查完成！共发现 " + violations.size() + " 个问题。");

        } catch (Exception e) {
            System.err.println("Checkstyle执行出错: " + e.getMessage());
            e.printStackTrace();
        }


    }

    /**
     * 打印检查结果
     */
    private static void printResults(List<Violation> violations) {
        if (violations.isEmpty()) {
            System.out.println("✓ 检查完成！未发现任何问题。");
            return;
        }

        System.out.println("==========================================");
        System.out.println("❌ 发现 " + violations.size() + " 个问题：");
        System.out.println("==========================================");

        // 按文件分组显示结果
        Map<String, List<Violation>> groupedViolations = new TreeMap<>();
        for (Violation violation : violations) {
            String fileName = new File(violation.getFileName()).getName();
            groupedViolations.computeIfAbsent(fileName, k -> new ArrayList<>()).add(violation);
        }

        for (Map.Entry<String, List<Violation>> entry : groupedViolations.entrySet()) {
            System.out.println("\n文件: " + entry.getKey());
            for (Violation v : entry.getValue()) {
                System.out.printf("  行 %4d: [%-20s] %s%n",
                        v.getLine(), v.getSource(), v.getMessage());
            }
        }

        System.out.println("\n==========================================");
        System.out.println("检查完成！共发现 " + violations.size() + " 个问题。");
    }

    /**
     * 自定义监听器收集违规信息
     */
    private static class ViolationCollector extends AbstractAutomaticBean implements AuditListener {
        private final List<Violation> violations = new ArrayList<>();
        // 新增统计字段
        private final Map<String, Integer> fileLines = new HashMap<>();
        private final Map<String, Integer> fileComments = new HashMap<>();

        @Override
        public void auditStarted(AuditEvent event) {}

        @Override
        public void auditFinished(AuditEvent event) {}

        @Override
        public void fileStarted(AuditEvent event) {}

        @Override
        public void fileFinished(AuditEvent event) {}

        @Override
        public void addError(AuditEvent event) {
            violations.add(new Violation(
                    event.getFileName(),
                    event.getLine(),
                    event.getSourceName(),
                    event.getMessage()
            ));

            // 捕获统计信息
            if (event.getSourceName().contains("CommentRatioCheck")) {
                String[] parts = event.getMessage().split(";");
                if (parts.length >= 2) {
                    String filename = event.getFileName();
                    try {
                        fileLines.put(filename, Integer.parseInt(parts[1].split("=")[1]));
                        fileComments.put(filename, Integer.parseInt(parts[2].split("=")[1]));
                    } catch (NumberFormatException e) {
                        System.err.println("解析统计信息失败: " + e.getMessage());
                    }

                }
            }
        }

        @Override
        public void addException(AuditEvent event, Throwable throwable) {
            violations.add(new Violation(
                    event.getFileName(),
                    event.getLine(),
                    "EXCEPTION",
                    throwable.getMessage()
            ));
        }

        public List<Violation> getViolations() {
            return violations;
        }

        @Override
        protected void finishLocalSetup() throws CheckstyleException {}

        // 添加统计方法
        public int getTotalLines() {
            return fileLines.values().stream().mapToInt(Integer::intValue).sum();
        }

        public int getTotalCommentLines() {
            return fileComments.values().stream().mapToInt(Integer::intValue).sum();
        }
    }

    /**
     * 违规信息封装类
     */
    private static class Violation {
        private final String fileName;
        private final int line;
        private final String source;
        private final String message;


        public Violation(String fileName, int line, String source, String message) {
            this.fileName = fileName;
            this.line = line;
            this.source = source;
            this.message = message;
        }

        public String getFileName() { return fileName; }
        public int getLine() { return line; }
        public String getSource() { return source; }
        public String getMessage() { return message; }
    }
}

